<!DOCTYPE html>
<html lang="zh">
	<head>
		<meta charset="UTF-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>浏览器渲染流程概述</title>
		<style>
			* {
				padding: 0;
				margin: 0;
			}

			.page {
				background: purple;
				color: white;
				margin: 20px;
				padding: 20px;
			}

			h2,
			h3,
			p {
				margin: 20px 0;
			}
		</style>
	</head>
	<body>
		<div class="page">
			<h2>
				浏览器渲染流程概述
			</h2>
			<h3>
				一、现代浏览器的页面渲染是一个复杂的多阶段过程，主要包含以下核心步骤‌：
			</h3>
			<p>
				1、解析HTML构建DOM树‌：浏览器将HTML字节流转换为Token，最终生成DOM树结构。遇到script标签时会阻塞解析（除非使用async或defer属性）‌。
			</p>
			<p>
				2、解析CSS构建CSSOM树‌：CSS解析器将样式规则转化为CSS对象模型，计算层叠样式表的优先级和继承关系‌。
			</p>
			<p>
				3、生成渲染树‌：将DOM树和CSSOM树合并，过滤掉不可见节点（如display:none），形成渲染树（Render Tree）‌。
			</p>
			<p>
				4、布局计算（Reflow）‌：计算每个元素在视口中的精确位置和尺寸，确定盒模型属性‌。
			</p>
			<p>
				5、绘制（Paint）‌：将布局结果转换为屏幕像素，涉及分层绘制和图层合成‌。
			</p>

			<h3>
				二、关键阶段详解
			</h3>
			<p>
				1. DOM树构建
				<br>
				采用渐进式解析，边下载边解析HTML‌
				<br>
				预加载扫描器并行查找外部资源（CSS/JS/图片）‌
				<br>
				同步JS会阻塞解析，异步JS（async/defer）可避免阻塞‌
			</p>
			<p>
				2. CSSOM构建
				<br>
				遵循选择器特异性规则：ID(100) > Class(10) > Element(1)‌
				<br>
				处理!important和继承属性（如font-size）‌
				<br>
				值标准化：将em/rem/百分比转换为像素‌
			</p>
			<p>
				3. 渲染树构建
				<br>
				仅包含可见节点（排除display:none）
				<br>
				包含伪元素（如::before）
				<br>
				合并DOM和CSSOM的样式计算结果‌
			</p>
			<p>
				4. 布局与重排
				<br>
				计算元素几何属性（位置/尺寸）‌
				<br>
				触发重排的操作包括：窗口大小调整、DOM修改、样式变更等‌
				<br>
				重排会触发重绘，但重绘不一定触发重排‌
			</p>
			<p>
				5. 绘制与合成
				<br>
				分层绘制：浏览器将页面分为多个图层优化渲染‌
				<br>
				光栅化：将矢量图形转换为位图‌
				<br>
				合成阶段合并各图层为最终图像
			</p>
			<h3>
				三、渲染为什么会阻塞？
			</h3>
			<p>
				浏览器渲染页面的过程，大致分为三个阶段：
				<br>
				1. 下载 HTML 并解析成 DOM 树
				<br>
				2. 下载 CSS 并解析成 CSSOM 树
				<br>
				3. 合并 DOM + CSSOM 生成 Render Tree，开始绘制页面
				<br>
				问题就在于：
				<br>
				• CSS 是渲染必须的资源，没有它，页面无法正确展示样式。
				<br>
				• JS 可能会修改 DOM 或 CSSOM，所以浏览器在执行 JS 之前，必须确定 CSS 是否就绪。
				<br>
				因此：
				<br>
				• 遇到 link rel="stylesheet"，浏览器必须停下来，等 CSS 加载完成，才能继续渲染。
				<br>
				• 遇到 script src="xxx.js"，如果没有 async 或 defer，浏览器会停下所有解析，等 JS 下载并执行完再继续。
				<br>
				这就是阻塞渲染和阻塞解析的原因。
			</p>
			<h3>
				四、CSS 链接的阻塞特点
			</h3>
			<p>
				• 阻塞渲染，不阻塞 HTML 解析
				<br>
				CSS 文件下载时，HTML 解析可以继续，但页面不会渲染出来，用户看到的是空白页面。
				<br>
				• 如果 CSS 后面有 JS，就会影响 JS 执行
				<br>
				因为 JS 可能依赖 CSSOM，浏览器必须等 CSS 下载并解析完成，才能执行 JS。

				<br>
				例如：
				<br>
				link rel="stylesheet" href="style.css"
				script src="main.js" script

				<br>
				这里 main.js 要等 style.css 完全下载并解析后才执行。
			</p>
			<h3>
				五、JS 链接的阻塞特点
			</h3>
			<p>
				• 阻塞 HTML 解析
				<br>
				当浏览器遇到 script src="xxx.js" 时，会暂停解析 HTML，先下载并执行 JS，再继续。
				<br>
				• 为什么这么做？
				<br>
				因为 JS 可能会修改 DOM（例如 document.write），所以必须等它执行完再解析后续内容。
			</p>
			<h3>
				六、怎么解决阻塞？
			</h3>
			<p>
				• CSS
				<br>
				放在 head，但可以合并、压缩、开启缓存，减少请求数量。
				<br>
				• JS
				<br>
				给 script 加 defer 或 async
				<br>
				• defer：HTML 解析完成后再执行，顺序不变。
				<br>
				• async：下载完成后立刻执行，顺序可能打乱。
			</p>
			<h3>
				七、总结
			</h3>
			<p>
				• CSS 阻塞渲染，但不阻塞 HTML 解析
				<br>
				• JS 阻塞 HTML 解析和渲染，除非使用 defer 或 async
				<br>
				优化的核心思路就是让 CSS 尽快加载，让 JS 延迟执行，这样页面渲染会更快，用户体验更好。

			</p>
		</div>
	</body>
</html>
